From 3f0a8ce1d77c3989f04a5a511832f07aed0c8561 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Jun 2007 11:19:55 +0100 Subject: [PATCH] hvm: Respect irqbase set by protected mode in mode switching with VMXAssist. RHEL4U4 PAE SMP guest currently crashes, and we found changeset 15214 introduced it. This patch fixes it. Signed-off-by: Xin Li Signed-off-by: Dexuan Cui --- tools/firmware/vmxassist/vm86.c | 6 +++++ tools/firmware/vmxassist/vm86.h | 4 ---- xen/arch/x86/hvm/vmx/vmx.c | 34 +++++++++++------------------ xen/arch/x86/hvm/vpic.c | 8 ++++++- xen/include/asm-x86/hvm/vmx/vmcs.h | 4 ++++ xen/include/public/hvm/vmx_assist.h | 6 +++++ 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index 78c1da0d88..d702c031cc 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -927,6 +927,7 @@ load_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs load_seg(0, base, limit, arbytes); } +static unsigned char rm_irqbase[2]; /* * Transition to protected mode @@ -936,6 +937,9 @@ protected_mode(struct regs *regs) { extern char stack_top[]; + oldctx.rm_irqbase[0] = rm_irqbase[0]; + oldctx.rm_irqbase[1] = rm_irqbase[1]; + regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM); oldctx.eip = regs->eip; @@ -1187,6 +1191,7 @@ outbyte(struct regs *regs, unsigned prefix, unsigned opc) icw2[0] = 0; printf("Remapping master: ICW2 0x%x -> 0x%x\n", al, NR_EXCEPTION_HANDLER); + rm_irqbase[0] = al; al = NR_EXCEPTION_HANDLER; } break; @@ -1200,6 +1205,7 @@ outbyte(struct regs *regs, unsigned prefix, unsigned opc) icw2[1] = 0; printf("Remapping slave: ICW2 0x%x -> 0x%x\n", al, NR_EXCEPTION_HANDLER+8); + rm_irqbase[1] = al; al = NR_EXCEPTION_HANDLER+8; } break; diff --git a/tools/firmware/vmxassist/vm86.h b/tools/firmware/vmxassist/vm86.h index ea8c2728d3..2cf3c0f7a5 100644 --- a/tools/firmware/vmxassist/vm86.h +++ b/tools/firmware/vmxassist/vm86.h @@ -26,10 +26,6 @@ #include -#define NR_EXCEPTION_HANDLER 32 -#define NR_INTERRUPT_HANDLERS 16 -#define NR_TRAPS (NR_EXCEPTION_HANDLER+NR_INTERRUPT_HANDLERS) - #ifndef __ASSEMBLY__ struct regs { diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 8a18202590..366110d19d 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2039,8 +2039,8 @@ enum { VMX_ASSIST_INVOKE = 0, VMX_ASSIST_RESTORE }; static int vmx_assist(struct vcpu *v, int mode) { struct vmx_assist_context c; - u32 magic; - u32 cp; + struct hvm_hw_vpic *vpic = v->domain->arch.hvm_domain.vpic; + u32 magic, cp; /* make sure vmxassist exists (this is not an error) */ if (hvm_copy_from_guest_phys(&magic, VMXASSIST_MAGIC_OFFSET, @@ -2074,20 +2074,11 @@ static int vmx_assist(struct vcpu *v, int mode) goto error; if ( vmx_world_restore(v, &c) != 0 ) goto error; + v->arch.hvm_vmx.pm_irqbase[0] = vpic[0].irq_base; + v->arch.hvm_vmx.pm_irqbase[1] = vpic[1].irq_base; + vpic[0].irq_base = NR_EXCEPTION_HANDLER; + vpic[1].irq_base = NR_EXCEPTION_HANDLER + 8; v->arch.hvm_vmx.vmxassist_enabled = 1; - /* - * The 32-bit vmxassist vm86.c support code is hard-coded to - * expect vPIC interrupts to arrive at interrupt traps 0x20-0x27 - * and 0x28-0x2f. It bounces these to 16-bit boot code traps - * 0x08-0x0f and 0x70-0x77. But when the guest transitions - * to true native 32-bit mode, vmxassist steps out of the - * way and no such bouncing occurs; so we need to rewrite - * the vPIC irq base to point directly to 0x08/0x70 (see - * code just below). So on re-entering 16-bit mode, we need - * to reset the vPICs to go back to the 0x20/0x28 bounce traps. - */ - v->domain->arch.hvm_domain.vpic[0].irq_base = 0x20; - v->domain->arch.hvm_domain.vpic[1].irq_base = 0x28; return 1; } break; @@ -2105,13 +2096,14 @@ static int vmx_assist(struct vcpu *v, int mode) goto error; if ( vmx_world_restore(v, &c) != 0 ) goto error; + if ( v->arch.hvm_vmx.irqbase_mode ) { + vpic[0].irq_base = c.rm_irqbase[0] & 0xf8; + vpic[1].irq_base = c.rm_irqbase[1] & 0xf8; + } else { + vpic[0].irq_base = v->arch.hvm_vmx.pm_irqbase[0]; + vpic[1].irq_base = v->arch.hvm_vmx.pm_irqbase[1]; + } v->arch.hvm_vmx.vmxassist_enabled = 0; - /* - * See comment above about vmxassist 16/32-bit vPIC behaviour. - * The irq_base values are hard-coded into vmxassist vm86.c. - */ - v->domain->arch.hvm_domain.vpic[0].irq_base = 0x08; - v->domain->arch.hvm_domain.vpic[1].irq_base = 0x70; return 1; } break; diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c index 5dfe1e4a6b..19ef5d0756 100644 --- a/xen/arch/x86/hvm/vpic.c +++ b/xen/arch/x86/hvm/vpic.c @@ -174,7 +174,8 @@ static int vpic_intack(struct hvm_hw_vpic *vpic) return irq; } -static void vpic_ioport_write(struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t val) +static void vpic_ioport_write( + struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t val) { int priority, cmd, irq; uint8_t mask; @@ -265,6 +266,11 @@ static void vpic_ioport_write(struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t vpic->imr = val; break; case 1: +#if 1 /* Delete me when vmxassist is retired. */ + /* Which mode is irqbase programmed in? */ + current->arch.hvm_vmx.irqbase_mode = + current->arch.hvm_vmx.vmxassist_enabled; +#endif /* ICW2 */ vpic->irq_base = val & 0xf8; vpic->init_state++; diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 93383559c5..88063214b8 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -79,7 +79,11 @@ struct arch_vmx_struct { unsigned long cstar; #endif unsigned long efer; + + /* Following fields are all specific to vmxassist. */ unsigned long vmxassist_enabled:1; + unsigned long irqbase_mode:1; + unsigned char pm_irqbase[2]; }; struct vmcs_struct *vmx_alloc_host_vmcs(void); diff --git a/xen/include/public/hvm/vmx_assist.h b/xen/include/public/hvm/vmx_assist.h index b07573c211..4ef17febff 100644 --- a/xen/include/public/hvm/vmx_assist.h +++ b/xen/include/public/hvm/vmx_assist.h @@ -35,6 +35,10 @@ #ifndef __ASSEMBLY__ +#define NR_EXCEPTION_HANDLER 32 +#define NR_INTERRUPT_HANDLERS 16 +#define NR_TRAPS (NR_EXCEPTION_HANDLER+NR_INTERRUPT_HANDLERS) + union vmcs_arbytes { struct arbyte_fields { unsigned int seg_type : 4, @@ -98,6 +102,8 @@ struct vmx_assist_context { uint32_t ldtr_limit; uint32_t ldtr_base; union vmcs_arbytes ldtr_arbytes; + + unsigned char rm_irqbase[2]; }; typedef struct vmx_assist_context vmx_assist_context_t; -- 2.30.2